﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Text.RegularExpressions;
using dotNetMembership=System.Web.Security.Membership;
using StarterKits.Mvc.Filters.FormsAuthentication;
using DotNetOpenId.RelyingParty;
using DotNetOpenId.Extensions;
using System.Web.Routing;

namespace StarterKits.Mvc.Membership.Controllers
{
	public abstract class BaseFormsAuthenticationController : Controller
	{

		#region Properties.
		protected AuthenticationMode DefaultAuthenticationMode = AuthenticationMode.Forms;
		protected List<AuthenticationMode> AllowedAuthenticationModes = new List<AuthenticationMode> { AuthenticationMode.Forms };
		protected enum AuthenticationMode
		{
			Forms,
			OpenID,
			WindowsLive
		}
		#endregion

		#region Utility/protected methods.

		[NonAction]
		public static void RegisterDefaultFormsRoutes( RouteCollection routes, string c, string extension )
		{
			routes.MapRoute( "FormsAuthentication_Login",
								"Login" + (extension ?? ""),
								new { controller = c, action = "Login" } );
			routes.MapRoute( "FormsAuthentication_Registration",
								"Register" + ( extension ?? "" ),
								new { controller = c, action = "Register" } );
			routes.MapRoute( "FormsAuthentication_PasswordRecovery",
								"ForgotPassword" + ( extension ?? "" ),
								new { controller = c, action = "PasswordRecovery" } );
			routes.MapRoute( "FormsAuthentication_PasswordQuestion",
								"PasswordQuestion" + ( extension ?? "" ),
								new { controller = c, action = "PasswordQuestion" } );
			routes.MapRoute( "FormsAuthentication_RetrievePassword",
								"RetrievePassword" + ( extension ?? "" ),
								new { controller = c, action = "RetrievePassword" } );
			routes.MapRoute( "FormsAuthentication_ResetPassword",
								"ResetPassword" + ( extension ?? "" ),
								new { controller = c, action = "ResetPassword" } );
		}

		[NonAction]
		public static void RegisterDefaultOpenIDRoutes( RouteCollection routes, string c, string extension )
		{
			routes.MapRoute( "OpenIDAuthentication_XRDS",
								"OpenID.xrds" + ( extension ?? "" ),
								new { controller = c, action = "OpenID_XRDS" } );
		}

		protected virtual void OnRedirectToActionWithErrorMessage( string action, string errorMessage ) { }

		protected ActionResult RedirectToActionWithErrorMessage( string action, string errorMessage )
		{
			OnRedirectToActionWithErrorMessage( action, errorMessage );
			TempData["ErrorMessage"] = errorMessage;
			return RedirectToAction( action, "FormsAuthentication" );
		}

		protected bool MatchesAnyInList( List<string> regexs, string text )
		{
			foreach( string regex in regexs )
			{
				Regex r = new Regex(regex);
				if( r.IsMatch(text) )
					return true;
			}
			return false;
		}

		#endregion

		#region User registration.

		[NonAction]
		protected virtual string OnBeforeCreateUser( string userName, string emailAddress, string password, string passwordQuestion, string passwordAnswer, string returnUrl, System.Collections.Specialized.NameValueCollection form ) { return null; }

		[NonAction]
		protected virtual void OnAfterCreateUser( MembershipUser user, string password, string passwordAnswer, string returnUrl, System.Collections.Specialized.NameValueCollection form ) { }

		[NonAction]
		protected virtual void OnCreateUserError( string userName, string emailAddress, string password, string passwordConfirm, string passwordQuestion, string passwordAnswer, string returnUrl, string error ) { }

		[RequiresAnonymous]
		public virtual ActionResult Register()
		{
			ViewData["MinimumPasswordLength"] = dotNetMembership.MinRequiredPasswordLength;
			ViewData["MinimumNonAlphaNumericCharacters"] = dotNetMembership.MinRequiredNonAlphanumericCharacters;
			ViewData["RequiresQuestionAndAnswer"] = dotNetMembership.RequiresQuestionAndAnswer;
			return View();
		}

		[RequiresAnonymous]
		public virtual ActionResult CreateUser( string userName, string emailAddress, string password, string passwordConfirm, string passwordQuestion, string passwordAnswer, string returnUrl )
		{

			string beforeRegistrationErrorMessage = OnBeforeCreateUser( userName, emailAddress, password, passwordQuestion, passwordAnswer, returnUrl, Request.Form );
			if( beforeRegistrationErrorMessage != null )
				return RedirectToActionWithErrorMessage( "Register", beforeRegistrationErrorMessage );

			try
			{

				// try to create user and then login that user

				if( password != passwordConfirm )
					throw new MembershipCreateUserException( "\"Password\" does not match \"Confirm Password\"." );

				MembershipCreateStatus status = MembershipCreateStatus.ProviderError;
				MembershipUser user = dotNetMembership.CreateUser( userName, password, emailAddress, passwordQuestion, passwordAnswer, true, out status );

				if( user == null )
					if( status != MembershipCreateStatus.Success )
						throw new MembershipCreateUserException( status.ToString() );
					else
						throw new MembershipCreateUserException( "An unspecified error occurred." );
				if( status != MembershipCreateStatus.Success )
					throw new MembershipCreateUserException( status.ToString() );

				FormsAuthentication.SetAuthCookie( userName, true );
				OnAfterCreateUser( user, password, passwordAnswer, returnUrl, Request.Form );
				return Redirect( returnUrl );

			}
			catch( MembershipCreateUserException e )
			{
				// something went wrong, pass the message down to the view
				OnCreateUserError( userName, emailAddress, password, passwordConfirm, passwordQuestion, passwordAnswer, returnUrl, e.Message );
				return RedirectToActionWithErrorMessage( "Register", e.Message );
			}
		}

		#endregion

		#region Login.

		public virtual ActionResult Login()
		{
			switch( DefaultAuthenticationMode )
			{
				case AuthenticationMode.Forms: return FormsLogin();
				case AuthenticationMode.OpenID: return OpenIDLogin();
				case AuthenticationMode.WindowsLive: return WindowsLiveLogin();
				default: throw new InvalidOperationException( "Unknown Authentication Mode Specified" );
			}
		}

		#endregion

		#region Login. (ASP.Net Forms)

		[NonAction]
		protected virtual void OnBeforeFormsAuthenticate( string userName, string password, string rememberMe, string returnUrl ) { }

		[NonAction]
		protected virtual void OnAfterFormsAuthenticate( string userName, string password, string rememberMe, string returnUrl ) { }

		[NonAction]
		protected virtual void OnFormsAuthenticateError( string userName, string password, string rememberMe, string returnUrl, string error ) { }

		public virtual ActionResult FormsLogin()
		{
			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.Forms ) )
				throw new UnauthorizedAccessException( "Forms Authentication Is Disabled" );
			ViewData["MinimumPasswordLength"] = dotNetMembership.MinRequiredPasswordLength;
			ViewData["MinimumNonAlphaNumericCharacters"] = dotNetMembership.MinRequiredNonAlphanumericCharacters;
			return View( "Login" );
		}

		[RequiresAnonymous]
		public virtual ActionResult FormsAuthenticate( string userName, string password, string rememberMe, string returnUrl )
		{

			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.Forms ) )
				throw new UnauthorizedAccessException( "Forms Authentication Is Disabled" );

			OnBeforeFormsAuthenticate( userName, password, rememberMe, returnUrl );

			// figure out if username and password are correct
			if( dotNetMembership.ValidateUser( userName, password ) )
			{
				// everything is good, create an authticket and go
				FormsAuthentication.SetAuthCookie( userName, ( rememberMe != null ) );
				OnAfterFormsAuthenticate( userName, password, rememberMe, returnUrl );
				return Redirect( returnUrl );
			}
			else
			{
				// something was wrong, figure out which and pass it into view
				string errorMessage = "";
				if( dotNetMembership.GetUser( userName ) == null )
				{
					errorMessage = "Incorrect username.";
					OnFormsAuthenticateError( userName, password, rememberMe, returnUrl, errorMessage );
					return RedirectToActionWithErrorMessage( "Login", errorMessage );
				}
				else
				{
					errorMessage = "Incorrect password.";
					OnFormsAuthenticateError( userName, password, rememberMe, returnUrl, errorMessage );
					return RedirectToActionWithErrorMessage( "Login", "Incorrect password." );
				}
			}
		}

		#endregion

		#region Login. (OpenID)

		[NonAction]
		protected virtual MembershipUser AssociateOpenIDToMembershipUser( string identity, SimpleRegistrationFieldValues registrationFields ) { return null; }

		[NonAction]
		protected virtual void OnBeforeOpenIDAuthenticate( string identity ) { }

		[NonAction]
		protected virtual void OnAfterOpenIDAuthenticate( string identity, MembershipUser user, SimpleRegistrationFieldValues registrationFields ) { }

		[NonAction]
		protected virtual void OnOpenIDAuthenticateError( string error ) { }

		public virtual ActionResult OpenIDLogin()
		{
			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.OpenID ) )
				throw new UnauthorizedAccessException( "OpenID Authentication Is Disabled" );
			return View( "OpenIDLogin" );
		}

		protected virtual SimpleRegistrationRequestFields GetOpenIDRegistrationFields()
		{
			SimpleRegistrationRequestFields fields = new SimpleRegistrationRequestFields();
			fields.FullName = SimpleRegistrationRequest.Request;
			fields.Email = SimpleRegistrationRequest.Request;
			return fields;
		}

		protected virtual List<string> GetOpenIDWhitelist()
		{
			return null;
		}

		[RequiresAnonymous]
		public virtual ActionResult OpenIDAuthenticate( string identity )
		{

			//### make sure we're allowed to use openid
			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.OpenID ) )
				throw new UnauthorizedAccessException( "OpenID Authentication Is Disabled" );

			//### get whitelist
			List<string> whitelist = GetOpenIDWhitelist();

			//### if rp.response is null, we're beginning our request, otherwise we're receiving our response
			OpenIdRelyingParty rp = new OpenIdRelyingParty();
			if( rp.Response == null )
			{

				//### verify identity against whitelist
				if( whitelist != null && whitelist.Count > 0 && !MatchesAnyInList( whitelist, rp.Response.ClaimedIdentifier ) )
				{
					OnOpenIDAuthenticateError( "OpenID Provider Not On Whitelist" );
					return RedirectToActionWithErrorMessage( "OpenIDLogin", "OpenID Provider Not On Whitelist" );
				}

				//### extensibility hook
				OnBeforeOpenIDAuthenticate( identity );

				//### try to connect to specified server
				IAuthenticationRequest req = null;
				try
				{
					req = rp.CreateRequest( identity );
				}
				catch( System.Net.WebException )
				{
					OnOpenIDAuthenticateError( "Could not connect to specified OpenID server." );
					return RedirectToActionWithErrorMessage( "OpenIDLogin", "Could not connect to specified OpenID server." );
				}

				//### tell dotnetopenid what attributes we want to query from the server
				SimpleRegistrationRequestFields fields = GetOpenIDRegistrationFields();
				fields.AddToRequest( req );

				//### redirect to the openid server
				return Redirect( req.RedirectToProviderUrl.ToString() );

			}
			else
			{

				//### verify identity against whitelist
				if( whitelist != null && whitelist.Count > 0 && !MatchesAnyInList( whitelist, identity ) )
				{
					OnOpenIDAuthenticateError( "OpenID Provider Not On Whitelist" );
					return RedirectToActionWithErrorMessage( "OpenIDLogin", "OpenID Provider Not On Whitelist" );
				}

				//### make sure the server says we're authenticated
				if( rp.Response.Exception != null )
				{
					OnOpenIDAuthenticateError( "OpenID Authentication Failed" );
					return RedirectToActionWithErrorMessage( "OpenIDLogin", "OpenID Authentication Failed: " + rp.Response.Exception.Message );
				}
				else if( rp.Response.Status == AuthenticationStatus.Authenticated )
				{

					//### retrieve attribute values from server response
					SimpleRegistrationFieldValues fields = SimpleRegistrationFieldValues.ReadFromResponse( rp.Response );

					//### try to associate this openid identity to a membership user
					MembershipUser user = AssociateOpenIDToMembershipUser( rp.Response.ClaimedIdentifier, fields );
					if( user == null )
					{
						OnOpenIDAuthenticateError( "Could not associate OpenID identity to a user in this system." );
						return RedirectToActionWithErrorMessage( "OpenIDLogin", "Could not associate OpenID identity to a user in this system." );
					}

					OnAfterOpenIDAuthenticate( rp.Response.ClaimedIdentifier, user, fields );

					//### set authorization cookie
					FormsAuthentication.SetAuthCookie( user.UserName, false );
					FormsAuthentication.RedirectFromLoginPage( user.UserName, false );
					return new EmptyResult();

				}
				else
				{
					OnOpenIDAuthenticateError( "OpenID Authentication Failed" );
					return RedirectToActionWithErrorMessage( "OpenIDLogin", "OpenID Authentication Failed" );
				}

			}

		}

		public ActionResult OpenID_XRDS()
		{
			return View();
		}

		#endregion

		#region Login. (Windows Live)

		[NonAction]
		protected virtual MembershipUser AssociateWindowsLiveIDToMembershipUser( string userId ) { return null; }

		[NonAction]
		protected virtual void OnBeforeWindowsLiveAuthenticate() { }

		[NonAction]
		protected virtual void OnAfterWindowsLiveAuthenticate( string userId, MembershipUser user ) { }

		[NonAction]
		protected virtual void OnWindowsLiveAuthenticateError( string error ) { }

		public virtual ActionResult WindowsLiveLogin()
		{
			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.WindowsLive ) )
				throw new UnauthorizedAccessException( "Windows Live Authentication Is Disabled" );
			return View( "WindowsLiveLogin" );
		}

		[RequiresAnonymous]
		public virtual ActionResult WindowsLiveAuthenticate()
		{

			if( !AllowedAuthenticationModes.Contains( AuthenticationMode.WindowsLive ) )
				throw new UnauthorizedAccessException( "Windows Live Authentication Is Disabled" );

			// initialize the WindowsLiveLogin module.
			WindowsLiveLogin wll = new WindowsLiveLogin( true );

			// communication channels
			HttpRequestBase request = this.HttpContext.Request;
			HttpResponseBase response = this.HttpContext.Response;

			// extract the 'action' parameter from the request, if any.
			string action = request["action"] ?? "";

			/*
			  If action is 'logout', clear the login cookie and redirect
			  to the logout page.

			  If action is 'clearcookie', clear the login cookie and
			  return a GIF as response to signify success.

			  By default, try to process a login. If login was
			  successful, cache the user token in a cookie and redirect
			  to the site's main page.  If login failed, clear the cookie
			  and redirect to the main page.
			*/
			if( action == "logout" )
			{
				HttpCookie loginCookie = new HttpCookie( "webauthtoken" );
				loginCookie.Expires = DateTime.Now.AddYears( -10 );
				response.Cookies.Add( loginCookie );
				return RedirectToAction( "WindowsLiveLogin" );
			}
			else if( action == "clearcookie" )
			{

				HttpCookie loginCookie = new HttpCookie( "webauthtoken" );
				loginCookie.Expires = DateTime.Now.AddYears( -10 );
				response.Cookies.Add( loginCookie );

				string type;
				byte[] content;
				wll.GetClearCookieResponse( out type, out content );
				response.ContentType = type;
				response.BinaryWrite( content );
				response.End();
				return new EmptyResult();

			}
			else
			{
				OnBeforeWindowsLiveAuthenticate();

				WindowsLiveLogin.User wllUser = wll.ProcessLogin( request.Form );

				HttpCookie loginCookie = new HttpCookie( "webauthtoken" );
				if( wllUser != null )
				{
					loginCookie.Value = wllUser.Token;

					if( wllUser.UsePersistentCookie )
					{
						loginCookie.Expires = DateTime.Now.AddYears( 10 );
					}
				}
				else
				{
					loginCookie.Expires = DateTime.Now.AddYears( -10 );
				}

				MembershipUser user = AssociateWindowsLiveIDToMembershipUser( wllUser.Id );
				if( user == null )
				{
					// could not find a user that mapped to that Windows Live ID
					string errorMessage = "Could not associate Windows Live ID with an active user account.";
					OnWindowsLiveAuthenticateError( errorMessage );
					return RedirectToActionWithErrorMessage( "WindowsLiveLogin", errorMessage );
				}
				else
				{
					// log user in
					response.Cookies.Add( loginCookie );
					FormsAuthentication.SetAuthCookie( user.UserName, false );

					// event hook
					OnAfterWindowsLiveAuthenticate( wllUser.Id, user );

					// redirect to user's original destination, or the default page as specified by FormsAuth
					//Response.Redirect(data.ReturnTo ?? returnUrl ?? FormsAuthentication.DefaultUrl);
					return RedirectToAction( "WindowsLiveLogin" );
				}
			}

		}

		#endregion

		#region Password recovery.

		[NonAction]
		protected virtual void OnBeforePasswordQuestion( string userName ) { }

		[NonAction]
		protected virtual void OnAfterPasswordQuestion( string userName, string passwordQuestion ) { }

		[NonAction]
		protected virtual void OnBeforeResetPassword( string userName, string passwordAnswer ) { }

		[NonAction]
		protected virtual void OnAfterResetPassword( string email, string userName, string newPassword ) { }

		[NonAction]
		protected virtual void OnBeforeRetrievePassword( string userName, string passwordAnswer ) { }

		[NonAction]
		protected virtual void OnAfterRetrievePassword( string email, string userName, string password ) { }

		[RequiresAnonymous]
		public virtual ActionResult PasswordRecovery()
		{
			ViewData["RequiresQuestionAndAnswer"] = dotNetMembership.RequiresQuestionAndAnswer;
			if( dotNetMembership.EnablePasswordReset )
				return View( "PasswordReset" );
			else if( dotNetMembership.EnablePasswordRetrieval )
				return View( "PasswordRetrieval" );
			else
				return Redirect( "~/" );
		}

		[RequiresAnonymous]
		public virtual ActionResult PasswordQuestion( string userName )
		{
			OnBeforePasswordQuestion( userName );

			// do we need this step?
			if( !dotNetMembership.RequiresQuestionAndAnswer )
			{
				if( dotNetMembership.EnablePasswordReset )
					ResetPassword( userName, "" );
				else if( dotNetMembership.EnablePasswordRetrieval ) { }
				RetrievePassword( userName, "" );
			}

			// determine view to use
			//string viewToUse = "";
			if( dotNetMembership.EnablePasswordReset )
			{
				ViewData["PostbackAction"] = "ResetPassword";
				//viewToUse = "PasswordReset";
			}
			else if( dotNetMembership.EnablePasswordRetrieval )
			{
				ViewData["PostbackAction"] = "RetrievePassword";
				//viewToUse = "PasswordRetrieve";
			}
			else
			{
				throw new InvalidOperationException( "Cannot reset or retrieve passwords." );
			}

			// the user for who we want the password question
			MembershipUser user = dotNetMembership.GetUser( userName );
			if( user == null )
			{
				if( dotNetMembership.EnablePasswordReset )
					return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username does not exist." );
				if( dotNetMembership.EnablePasswordRetrieval )
					return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username does not exist." );
				return Redirect( "~/" );
			}

			OnAfterPasswordQuestion( userName, user.PasswordQuestion );

			// password question
			ViewData["UserName"] = userName;
			ViewData["PasswordQuestion"] = user.PasswordQuestion;
			return View( "PasswordQuestion" );

		}

		[RequiresAnonymous]
		public virtual ActionResult ResetPassword( string userName, string passwordAnswer )
		{
			OnBeforeResetPassword( userName, passwordAnswer );

			// make sure password reset is enabled
			if( !dotNetMembership.EnablePasswordReset )
				throw new MemberAccessException( "Password reset is not enabled." );

			// the user requesting a password reset
			MembershipUser user = null;

			// verify if all parameters are passed
			if( string.IsNullOrEmpty( userName ) )
				return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username is required." );
			else
			{
				// fetch the user
				user = dotNetMembership.GetUser( userName );
				if( user == null )
					return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username does not exist." );
			}
			if( dotNetMembership.RequiresQuestionAndAnswer && string.IsNullOrEmpty( passwordAnswer ) )
			{
				ViewData["ErrorMessage"] = "Password answer is required.";
				return PasswordQuestion( userName );
			}

			string password = "";
			try
			{
				// try to generate a new password for the user
				password = user.ResetPassword( passwordAnswer );
			}
			catch( MembershipPasswordException e )
			{
				// something went wrong, pass the message down to the view
				return RedirectToActionWithErrorMessage( "PasswordRecovery", e.Message );
			}

			OnAfterResetPassword( user.Email, userName, password );

			// success!
			return View( "PasswordEmailed" );

		}

		[RequiresAnonymous]
		public virtual ActionResult RetrievePassword( string userName, string passwordAnswer )
		{

			OnBeforeRetrievePassword( userName, passwordAnswer );

			// make sure password retrieval is enabled
			if( !dotNetMembership.EnablePasswordRetrieval )
				throw new MemberAccessException( "Password retrieval is not enabled." );

			// the user requesting a password reset
			MembershipUser user = null;

			// verify if all parameters are passed
			if( string.IsNullOrEmpty( userName ) )
				return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username is required." );
			else
			{
				// fetch the user
				user = dotNetMembership.GetUser( userName );
				if( user == null )
					return RedirectToActionWithErrorMessage( "PasswordRecovery", "Username does not exist." );
			}
			if( dotNetMembership.RequiresQuestionAndAnswer )
			{
				if( string.IsNullOrEmpty( passwordAnswer ) )
				{
					ViewData["ErrorMessage"] = "Password answer is required.";
					return PasswordQuestion( userName );
				}
			}

			string password = "";
			try
			{
				// retrieve password for the user
				password = user.GetPassword( passwordAnswer );
			}
			catch( MembershipPasswordException e )
			{
				// something went wrong, pass the message down to the view
				return RedirectToActionWithErrorMessage( "PasswordRecovery", e.Message );
			}

			OnAfterRetrievePassword( user.Email, userName, password );

			// success!
			return View( "PasswordEmailed" );

		}

		#endregion

		#region Change password.

		[NonAction]
		protected virtual void OnBeforePasswordChange( string userName, string currentPassword, string newPassword, string newPasswordConfirm ) { }

		[NonAction]
		protected virtual void OnAfterPasswordChange( string userName, string currentPassword, string newPassword, string newPasswordConfirm ) { }

		[RequiresAuthentication]
		public virtual ActionResult PasswordChange()
		{
			ViewData["userName"] = dotNetMembership.GetUser().UserName;
			ViewData["MinimumPasswordLength"] = dotNetMembership.MinRequiredPasswordLength;
			ViewData["MinimumNonAlphaNumericCharacters"] = dotNetMembership.MinRequiredNonAlphanumericCharacters;
			return View( "PasswordChange" );
		}

		[RequiresAuthentication]
		public virtual ActionResult ChangePassword( string currentPassword, string newPassword, string newPasswordConfirm )
		{
			OnBeforePasswordChange( this.HttpContext.User.Identity.Name, currentPassword, newPassword, newPasswordConfirm );

			// verify if all parameters are passed
			if( string.IsNullOrEmpty( currentPassword ) )
				return RedirectToActionWithErrorMessage( "PasswordChange", "Current password is required." );
			else if( string.IsNullOrEmpty( newPassword ) || string.IsNullOrEmpty( newPasswordConfirm ) )
				return RedirectToActionWithErrorMessage( "PasswordChange", "New password is required." );
			else if( newPassword != newPasswordConfirm )
				return RedirectToActionWithErrorMessage( "PasswordChange", "New password does not match new password confirmation." );

			// the user that wants to update his password
			MembershipUser user = dotNetMembership.GetUser();
			if( user == null )
				return RedirectToActionWithErrorMessage( "PasswordChange", "User not found." );

			try
			{
				// update the user's password
				if (!user.ChangePassword( currentPassword, newPassword ))
                    return RedirectToActionWithErrorMessage("PasswordChange", "Password change failed.");
			}
			catch( MembershipPasswordException e )
			{
				// something went wrong, pass the message down to the view
				return RedirectToActionWithErrorMessage( "PasswordChange", e.Message );
			}

			OnAfterPasswordChange( this.HttpContext.User.Identity.Name, currentPassword, newPassword, newPasswordConfirm );

			// success!
			ViewData["Success"] = true;
            ViewData["userName"] = dotNetMembership.GetUser().UserName;
            ViewData["MinimumPasswordLength"] = dotNetMembership.MinRequiredPasswordLength;
            ViewData["MinimumNonAlphaNumericCharacters"] = dotNetMembership.MinRequiredNonAlphanumericCharacters;
			return View( "PasswordChange" );

		}

		#endregion

		#region Logout.

		[NonAction]
		protected virtual void OnLoggingOut() { }

		[NonAction]
		protected virtual void OnLoggedOut() { }

		[RequiresAuthentication]
		public virtual ActionResult Logout()
		{

			OnLoggingOut();
			FormsAuthentication.SignOut();

			// Windows Live ID logout...
			HttpCookie loginCookie = new HttpCookie( "webauthtoken" );
			loginCookie.Expires = DateTime.Now.AddYears( -10 );
			this.HttpContext.Response.Cookies.Add( loginCookie );

			OnLoggedOut();
			return Redirect( FormsAuthentication.DefaultUrl );

		}

		#endregion

	}
}